package com.jfinal.weixin.lbs.util;


import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.PropKit;
import com.jfinal.weixin.lbs.model.BaiduPlace;
import com.jfinal.weixin.lbs.model.InLocationBean;
import com.jfinal.weixin.sdk.msg.out.News;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 百度地图操作类 javabase64-1.3.1.jar
 */
public class BaiduMapUtil {
    /**
     * 圆形区域检索
     *
     * @param query 检索关键词
     * @param lng   经度
     * @param lat   纬度
     * @return List<BaiduPlace>
     */
    public static List<BaiduPlace> searchPlace(String query, String lat, String lng) {
        // 拼装请求地址
        String requestUrl = "http://api.map.baidu.com/place/v2/search?&query=QUERY&location={LAT},{LNG}&radius=2000&output=xml&scope=2&page_size=10&page_num=0&ak=" + PropKit.get(BaiduLBSUtil.AK);
        try {
            requestUrl = requestUrl.replace("QUERY", URLEncoder.encode(query, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("encode error:", e);
        }
        requestUrl = requestUrl.replace("{LAT}", lat);
        requestUrl = requestUrl.replace("{LNG}", lng);
        /* 调用Place API圆形区域检索 */
        String respXml = httpRequest(requestUrl);
        // 解析返回的xml
        return parsePlaceXml(respXml);
    }

    /**
     * 发送http请求
     *
     * @param requestUrl 请求地址
     * @return String
     */
    public static String httpRequest(String requestUrl) {
        StringBuilder buffer = new StringBuilder();
        try {
            URL url = new URL(requestUrl);
            HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
            httpUrlConn.setDoInput(true);
            httpUrlConn.setRequestMethod("GET");
            httpUrlConn.connect();

            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            httpUrlConn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return buffer.toString();
    }

    /**
     * 根据百度地图返回的流解析出地址信息
     *
     * @param xml 输入流
     * @return List<BaiduPlace>
     */
    private static List<BaiduPlace> parsePlaceXml(String xml) {
        List<BaiduPlace> placeList = null;
        try {
            Document document = DocumentHelper.parseText(xml);
            // 得到xml根元素
            Element root = document.getRootElement();
            // 从根元素获取<results>
            Element resultsElement = root.element("results");
            // 从<results>中获取<result>集合
            List<Element> resultElementList = resultsElement.elements("result");
            // 判断<result>集合的大小
            if (resultElementList.size() > 0) {
                placeList = new ArrayList<BaiduPlace>();
                // POI名称
                Element nameElement;
                // POI地址信息
                Element addressElement;
                // POI经纬度坐标
                Element locationElement;
                // POI电话信息
                Element telephoneElement;
                // POI扩展信息
                Element detailInfoElement;
                // 距离中心点的距离
                Element distanceElement;
                // 遍历<result>集合
                for (Element resultElement : resultElementList) {
                    nameElement = resultElement.element("name");
                    addressElement = resultElement.element("address");
                    locationElement = resultElement.element("location");
                    telephoneElement = resultElement.element("telephone");
                    detailInfoElement = resultElement.element("detail_info");

                    BaiduPlace place = new BaiduPlace();
                    place.setName(nameElement.getText());
                    place.setAddress(addressElement.getText());
                    place.setLng(locationElement.element("lng").getText());
                    place.setLat(locationElement.element("lat").getText());
                    // 当<telephone>元素存在时获取电话号码
                    if (null != telephoneElement)
                        place.setTelephone(telephoneElement.getText());
                    // 当<detail_info>元素存在时获取<distance>
                    if (null != detailInfoElement) {
                        distanceElement = detailInfoElement.element("distance");
                        if (null != distanceElement)
                            place.setDistance(Integer.parseInt(distanceElement.getText()));
                    }
                    placeList.add(place);
                }
                // 按距离由近及远排序
                Collections.sort(placeList);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return placeList;
    }

    /**
     * 根据Place组装图文列表
     *
     * @param placeList 列表
     * @param longitude 经度
     * @param latitude  纬度
     * @return List<Article>
     */
    public static List<News> makeArticleList(String basePath, List<BaiduPlace> placeList, String latitude, String longitude) {
        // 项目的根路径
        List<News> list = new ArrayList<News>();
        BaiduPlace place;
        for (int i = 0; i < placeList.size(); i++) {
            place = placeList.get(i);
            News article = new News();
            article.setTitle(place.getName() + "\n距离约" + place.getDistance() + "米");
            // P1表示用户发送的位置（坐标转换后），p2表示当前POI所在位置
            article.setUrl(String.format("%s/jsp/route.jsp?p1=%s,%s&p2=%s,%s", basePath, longitude, latitude, place.getLng(),
                    place.getLat()));
            // 将首条图文的图片设置为大图
            if (i == 0)
                article.setPicUrl(basePath + "/img/poisearch.png");
            else
                article.setPicUrl(basePath + "/img/navi.png");
            list.add(article);
        }
        return list;
    }


    /**
     * 騰迅火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
     *
     * @param old
     */
    public static InLocationBean gcj02_To_Bd09(InLocationBean old) {
        double pi = Math.PI;
        double x = Double.valueOf(old.getLatitude()),
                y = Double.valueOf(old.getLongitude());
        double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi);
        double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi);
        double longitude = z * Math.cos(theta) + 0.0065;
        double latitude = z * Math.sin(theta) + 0.006;
        return new InLocationBean(String.valueOf(latitude), String.valueOf(longitude), old.getAddress());
    }

    /**
     * 将微信定位的坐标转换成百度坐标（GCJ-02 -> Baidu）
     *
     * @param old
     * @return UserLocation
     */
    public static InLocationBean convertCoord(InLocationBean old) {
        // 百度坐标转换接口
        String convertUrl = "http://api.map.baidu.com/geoconv/v1/?coords={longitude},{latitude}&from=1&to=5&ak=" + PropKit.get(BaiduLBSUtil.AK);
        convertUrl = convertUrl.replace("{latitude}", old.getLatitude());
        convertUrl = convertUrl.replace("{longitude}", old.getLongitude());

        InLocationBean location = old;
        String jsonCoord = httpRequest(convertUrl);
        JSONObject result = JSONObject.parseObject(jsonCoord);
        // 对转换后的坐标进行Base64解码
        if (result.getInteger("status") != 0) {
            throw new RuntimeException(result.toString());
        } else {
            String x = result.getJSONArray("result").getJSONObject(0).getString("x");
            String y = result.getJSONArray("result").getJSONObject(0).getString("y");
            location.setLatitude(y);
            location.setLongitude(x);
        }
        return location;
    }

}
